﻿#ifndef CAMERABASE_H
#define CAMERABASE_H

#include <QObject>
#include <QImage>
#include <QMutex>
#include <QMap>
#include <QDataStream>

#pragma execution_character_set("utf-8")

enum CameraBrand{
    CB_HiK = 0,
    CB_Basler,
    CB_DaHua,
    CB_DaHeng,
    CB_Ik
};
Q_DECLARE_METATYPE(CameraBrand)

enum CameraErrorCode{
    CEC_Remove = 0,
    CEC_ImgError,
};
Q_DECLARE_METATYPE(CameraErrorCode)

enum CameraStatus{
    CS_Unavailable=0,
    CS_Opened,
    CS_Grabbing,
    CS_Closed,
    CS_Closing,
};
Q_DECLARE_METATYPE(CameraStatus)

enum CameraTriggerType{
    CTT_Off = 0,
    CTT_Line0,
    CTT_Line1,
    CTT_Line2,
    CTT_Line3,
    CTT_Software,
    CTT_FrequencyConverter,
};
Q_DECLARE_METATYPE(CameraTriggerType)

struct IntValue{
    int val;
    int min;
    int max;
    int inc;
    IntValue(){
        val = 100;
        min = 0;
        max = 10000;
        inc = 1;
    }
    friend QDataStream &operator<<(QDataStream &out, const IntValue &value){
        out << value.val
            << value.min
            << value.max
            << value.inc;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, IntValue &value){
        in  >> value.val
            >> value.min
            >> value.max
            >> value.inc;
        return in;
    }
};
Q_DECLARE_METATYPE(IntValue)

struct FloatValue{
    float val;
    float min;
    float max;
    FloatValue(){
        val = 100;
        min = 0;
        max = 10000;
    }
    friend QDataStream &operator<<(QDataStream &out, const FloatValue &value){
        out << value.val
            << value.min
            << value.max;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, FloatValue &value){
        in  >> value.val
            >> value.min
            >> value.max;
        return in;
    }
};
Q_DECLARE_METATYPE(FloatValue)

struct CameraTrigger{
    CameraTriggerType frameMode;
    FloatValue frameDelay;
    CameraTriggerType lineMode;
    CameraTrigger() : frameMode(CTT_Line0), frameDelay(FloatValue()), lineMode(CTT_FrequencyConverter){
    }
    friend QDataStream &operator<<(QDataStream &out, const CameraTrigger &trig){
        out << trig.frameMode
            << trig.frameDelay
            << trig.lineMode
            ;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, CameraTrigger &trig){
        in  >> trig.frameMode
            >> trig.frameDelay
            >> trig.lineMode
            ;
        return in;
    }
};
Q_DECLARE_METATYPE(CameraTrigger)

struct CameraBrightness{
    int expMode;
    FloatValue exp; //exposure
    int gainMode;
    FloatValue gain; //gain
    CameraBrightness() : expMode(0), exp(FloatValue()), gainMode(0), gain(FloatValue()){
    }
    friend QDataStream &operator<<(QDataStream &out, const CameraBrightness &bri){
        out << bri.expMode
            << bri.exp
            << bri.gainMode
            << bri.gain;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, CameraBrightness &bri){
        in  >> bri.expMode
            >> bri.exp
            >> bri.gainMode
            >> bri.gain;
        return in;
    }
};
Q_DECLARE_METATYPE(CameraBrightness)

struct CameraROI{
    IntValue offX; //roi x offset
    IntValue offY; //roi y offset
    IntValue width; //roi width
    IntValue height; //roi height
    CameraROI() : offX(IntValue()), offY(IntValue()), width(IntValue()), height(IntValue()){
    }
    friend QDataStream &operator<<(QDataStream &out, const CameraROI &roi){
        out << roi.offX
            << roi.offY
            << roi.width
            << roi.height;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, CameraROI &roi){
        in  >> roi.offX
            >> roi.offY
            >> roi.width
            >> roi.height;
        return in;
    }
};
Q_DECLARE_METATYPE(CameraROI)

struct CameraFrameRate{
    bool rateControl;
    FloatValue rate;
    CameraFrameRate() : rateControl(false), rate(FloatValue()){
    }
    friend QDataStream &operator<<(QDataStream &out, const CameraFrameRate &rate){
        out << rate.rateControl
            << rate.rate;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, CameraFrameRate &rate){
        in  >> rate.rateControl
            >> rate.rate;
        return in;
    }
};
Q_DECLARE_METATYPE(CameraFrameRate)


struct CameraTrans{
    bool reverseX; //roi x reverse
    bool reverseY; //roi y reverse
    CameraTrans() : reverseX(false), reverseY(false){
    }
    friend QDataStream &operator<<(QDataStream &out, const CameraTrans &trans){
        out << trans.reverseX
            << trans.reverseY;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, CameraTrans &trans){
        in  >> trans.reverseX
            >> trans.reverseY;
        return in;
    }
};
Q_DECLARE_METATYPE(CameraTrans)

struct CameraWhiteBalance{
    int wbMode;
    IntValue wbR;  //white balance red
    IntValue wbG;  //white balance green
    IntValue wbB;  //white balance blue
    CameraWhiteBalance() : wbMode(0), wbR(IntValue()), wbG(IntValue()), wbB(IntValue()){
    }
    friend QDataStream &operator<<(QDataStream &out, const CameraWhiteBalance &wb){
        out << wb.wbMode
            << wb.wbR
            << wb.wbG
            << wb.wbB;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, CameraWhiteBalance &wb){
        in  >> wb.wbMode
            >> wb.wbR
            >> wb.wbG
            >> wb.wbB;
        return in;
    }
};
Q_DECLARE_METATYPE(CameraWhiteBalance)

struct FrequencyConverter{
    IntValue preDiv;
    IntValue mul;
    IntValue postDiv;
    FrequencyConverter() : preDiv(IntValue()), mul(IntValue()), postDiv(IntValue()){
    }
    friend QDataStream &operator<<(QDataStream &out, const FrequencyConverter &fc){
        out << fc.preDiv
            << fc.mul
            << fc.postDiv;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, FrequencyConverter &fc){
        in  >> fc.preDiv
            >> fc.mul
            >> fc.postDiv;
        return in;
    }
};
Q_DECLARE_METATYPE(FrequencyConverter)

struct CameraConfig{
    QString name;
    CameraBrand brand;
    bool isLine;
    bool isColor;
    CameraTrigger trig;
    CameraBrightness bright;
    CameraFrameRate rate;
    CameraROI roi;
    CameraTrans trans;
    CameraWhiteBalance wb;
    FrequencyConverter fc;
    CameraConfig() : name("Camera1"), isLine(false), isColor(false), trig(CameraTrigger()), bright(CameraBrightness()), rate(CameraFrameRate()),
        roi(CameraROI()), trans(CameraTrans()), wb(CameraWhiteBalance()), fc(FrequencyConverter()){
    }
    friend QDataStream &operator<<(QDataStream &out, const CameraConfig &config){
        out << config.name
            << config.brand
            << config.isLine
            << config.isColor
            << config.trig
            << config.bright
            << config.rate
            << config.roi
            << config.trans
            << config.wb
            << config.fc;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, CameraConfig &config){
        in  >> config.name
            >> config.brand
            >> config.isLine
            >> config.isColor
            >> config.trig
            >> config.bright
            >> config.rate
            >> config.roi
            >> config.trans
            >> config.wb
            >> config.fc;
        return in;
    }
};
Q_DECLARE_METATYPE(CameraConfig)

struct ImageInfo{
    unsigned int nWidth;        //图像宽
    unsigned int nHeight;       //图像高
    unsigned char *pData;       //图像数据
    unsigned int nDataLen;      //图像大小（字节数）
    unsigned int enPixelType;   //图像格式
};
Q_DECLARE_METATYPE(ImageInfo)


class CameraBase : public QObject
{
    Q_OBJECT
public:
    CameraBase(QObject *parent = nullptr);
    virtual ~CameraBase();
    QString getName() const {return mCamConfig.name;}
    CameraStatus getStatus() const { return mStatus;}
    void setStatus(const CameraStatus &status);
    bool getReceiveStatus(){return mIsReceive;}
    void reStart();
    void setConfig(const CameraConfig& config);

public slots:
    void onGrabReceiveStart(bool isStart){mIsReceive = isStart;}
    virtual void onInit();
    virtual void initialize()=0;
    virtual void openCamera()=0;
    virtual void startGrabbing() = 0;
    virtual void stopGrabbing() = 0;
    virtual void closeCamera()=0;
    virtual void releaseCamera()=0;
    virtual void quit();
    virtual void preProcessImage(const ImageInfo& imgInfo)=0;
    virtual QStringList enumCameraList(){return QStringList();}

    virtual void readConfig(const QString& camName);
    virtual void onConfigChanged(const CameraConfig& config);

    virtual void readROI(const QString& camName);
    virtual void readWhiteBalance(const QString& camName);
    virtual void readBrightness(const QString& camName);
    virtual void readTrigger(const QString& camName);
    virtual void readTrans(const QString& camName);
    virtual void readFrameRate(const QString& camName);
    virtual void readFrequencyConverter(const QString& camName);

    virtual void setROI(const QString& camName, const CameraROI &roi);
    virtual void setWhiteBalance(const QString& camName, const CameraWhiteBalance &cw);
    virtual void setBrightness(const QString& camName, const CameraBrightness &cb);
    virtual void setTrigger(const QString& camName, const CameraTrigger &ct);
    virtual void setTrans(const QString& camName, const CameraTrans &cts);
    virtual void setFrameRate(const QString& camName, const CameraFrameRate &cfr);
    virtual void setFrequencyConverter(const QString& camName, const FrequencyConverter &cfc);

    //trigger
    virtual void triggerSoftware(){}//软触发
    virtual void setFrameTriggerMode(const QString& camName, const CameraTriggerType &type){}
    virtual void setFrameTriggerDelay(const QString& camName, const float &delay){}
    virtual void setLineTriggerMode(const QString& camName, const CameraTriggerType &type){}
    virtual void setTriggerMode(const QString &camName, const CameraTriggerType &type){}

    //ROI
    virtual void setWidth(const QString& camName, const int& width){}
    virtual void setHeight(const QString& camName, const int& height){}
    virtual void setOffsetX(const QString& camName, const int& offX){}
    virtual void setOffsetY(const QString& camName, const int& offY){}
    //Trans
    virtual void setReverseX(const QString& camName, const bool& reverseX){}
    virtual void setReverseY(const QString& camName, const bool& reverseY){}

    //white balance
    virtual void setWhiteBalanceMode(const QString& camName, const int &mode){}
    virtual void setWhiteBalanceR(const QString& camName, const int &wbR){}
    virtual void setWhiteBalanceG(const QString& camName, const int &wbG){}
    virtual void setWhiteBalanceB(const QString& camName, const int &wbB){}
    //Brightness
    virtual void setExposureAutoMode(const QString& camName, const int &expMode){}
    virtual void setExposureTime(const QString& camName, const float &exp){}
    virtual void setGainMode(const QString& camName, const int &gainMode){}
    virtual void setGain(const QString& camName, const float &gain){}
    //帧率控制
    virtual void setFrameRateControl(const QString& camName, const bool& control){}
    virtual void setFrameRate(const QString& camName, const float &rate){}
    //分倍频
    virtual void setPreDiv(const QString& camName, const int& preDiv){}
    virtual void setMul(const QString& camName, const int& mul){}
    virtual void setPostDiv(const QString& camName, const int& postDiv){}

    virtual int getPixelFormat() = 0;
    virtual bool isColor(int pixelFormat) = 0;

    virtual int getScanType() = 0;
    virtual bool isLineScan(int scanType) = 0;

    //trigger
    virtual CameraTriggerType getFrameTriggerMode(const QString& camName){return CTT_Off;}
    virtual FloatValue getFrameTriggerDelay(const QString& camName){return FloatValue();}
    virtual CameraTriggerType getLineTriggerMode(const QString& camName){return CTT_Off;}
    virtual CameraTriggerType getTriggerMode(const int &mode, const int& source){return CTT_Off;}

    //ROI
    virtual IntValue getWidth(const QString& camName){return IntValue();}
    virtual IntValue getHeight(const QString& camName){return IntValue();}
    virtual IntValue getOffsetX(const QString& camName){return IntValue();}
    virtual IntValue getOffsetY(const QString& camName){return IntValue();}
    //Trans
    virtual bool getReverseX(const QString& camName){return 0;}
    virtual bool getReverseY(const QString& camName){return 0;}

    //white balance
    virtual int getWhiteBalanceMode(const QString& camName){return 0;}
    virtual IntValue getWhiteBalanceR(const QString& camName){return IntValue();}
    virtual IntValue getWhiteBalanceG(const QString& camName){return IntValue();}
    virtual IntValue getWhiteBalanceB(const QString& camName){return IntValue();}
    //Brightness
    virtual int getExposureAutoMode(const QString& camName){return 0;}
    virtual FloatValue getExposureTime(const QString& camName){return FloatValue();}
    virtual int getGainMode(const QString& camName){return 0;}
    virtual FloatValue getGain(const QString& camName){return FloatValue();}
    //帧率控制
    virtual bool getFrameRateControl(const QString& camName){return 0;}
    virtual FloatValue getFrameRate(const QString& camName){return FloatValue();}
    //分倍频
    virtual IntValue getPreDiv(const QString& camName){return IntValue();}
    virtual IntValue getMul(const QString& camName){return IntValue();}
    virtual IntValue getPostDiv(const QString& camName){return IntValue();}


signals:
    void sigImage(const QString& camName,QImage image);
    void sigErrorOccured(const QString& camName, CameraErrorCode errCode);
    void sigStatusChanged(const QString& camName, CameraStatus status);
    void sigStartSucceed(const QString& camName);

    void sigConfig(const CameraConfig& config);
    void sigROI(const QString& camName, const CameraROI& cp);
    void sigWhiteBalance(const QString& camName, const CameraWhiteBalance& cp);
    void sigBrightness(const QString& camName, const CameraBrightness& cp);
    void sigTrigger(const QString& camName, const CameraTrigger& cp);
    void sigTrans(const QString& camName, const CameraTrans& cp);
    void sigFrameRate(const QString& camName, const CameraFrameRate& cp);
    void sigFrequencyConverter(const QString& camName, const FrequencyConverter& fc);

public:
    static QMap<CameraStatus, QString> mapStatusStr;
    static QMap<CameraTriggerType, QString> mapTrigModeStr;
    static QMap<CameraErrorCode, QString> mapErrorCodeStr;
    static QMap<int, QString> mapWBModeStr;
    static QMap<int, QString> mapExpAutoStr;
    static QMap<int, QString> mapGainModeStr;
    static QMap<int, QString> mapCameraBrand;
    static void initStaticValue();

protected:
    QMutex mLock;
    int mReconnectMax = 1000;
    int mReconnectCnt = 0;
    CameraStatus mStatus = CS_Unavailable;
    bool mIsQuit = false;
    bool mIsReceive = true;
    CameraConfig mCamConfig;
};

#endif // CAMERABASE_H
